home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / pctjdc85.arc / COMM.PAS < prev    next >
Pascal/Delphi Source File  |  1985-10-21  |  7KB  |  219 lines

  1. Program Comm;
  2.  
  3. Type INS8250 = Record          {Define serial port registers}
  4.                  THR:Integer;     {Transmit holding register}
  5.                  RBR:Integer;     {Receive holding register}
  6.                  IER:Integer;     {Interrupt enable register}
  7.                  LCR:Integer;     {Line control register}
  8.                  MCR:Integer;     {Modem control register}
  9.                  LSR:Integer;     {Line status register}
  10.                  MSR:Integer;     {Modem status register}
  11.                End;
  12.  
  13.      Registers = Record    {Define the 8086 chip registers}
  14.                    AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags:Integer;
  15.                  End;
  16.  
  17.      Baud = (B110,B150,B300,B600,B1200,B2400,B4800,B9600);
  18.  
  19.      Parity = (None,Odd,Nevermind,Even);
  20.  
  21.      {Define addresses for COM1 & COM2}
  22. Const RS232:Array [1..2] of INS8250 =
  23.               ((THR:$3F8;RBR:$3F8;IER:$3F9;
  24.                 LCR:$3FB;MCR:$3FC;LSR:$3FD;MSR:$3FE),
  25.                (THR:$2F8;RBR:$2F8;IER:$2F9;
  26.                 LCR:$2FB;MCR:$2FC;LSR:$2FD;MSR:$2FE));
  27.  
  28. Var COM:Byte;                       {COM1 = 1 and COM2 = 2}
  29.     RS_Error:Byte;                  {Error from serial port}
  30.     Buffer:Array [0..4095] of Byte; {4K data comm. buffer}
  31.     Buf_Head,Buf_Tail:Integer;      {Head/tail buffer pointers}
  32.     Regs:Registers;                 {Passes parms to MSDOS}
  33.     Char_In:Integer;                {Char read from serial port}
  34.  
  35. Const Data_Segment:Integer = 0;     {Holds contents of DS reg.}
  36.  
  37.  
  38. Function Keyin:Integer;
  39. Var Key:Byte;
  40.  
  41.      {This function reads in one keystroke from the keyboard.
  42.       If a normal key was pressed, the value is returned in the
  43.       low order byte of the integer value. If an "extended" key
  44.       (such as a function key) was pressed, the low order byte
  45.       contains a zero and the high order byte contains the
  46.       extended code}
  47.  
  48.    Begin
  49.      Regs.AX:=$0700;
  50.      MSDos(Regs);
  51.      Key:=Lo(Regs.AX);
  52.      If Key = 0 then
  53.        Keyin:=Keyin*256
  54.      else
  55.        Keyin:=Key;
  56.    End;  {of Keyin}
  57.  
  58.  
  59. Procedure RS232_Interrupt;
  60.  
  61.      {This procedure handles interrupts from the serial port.
  62.       RS_Error is set to reflect any error result from the port,
  63.       but nothing is done with this. The character is read in
  64.       from the port and stored in the buffer and Buf_Tail is
  65.       incremented.  No test is made for buffer overflow.
  66.       After all registers have been pushed, the data segment
  67.       containing global data is loaded into DX from the
  68.       typed constant Data_Segment.}
  69.  
  70.    Begin
  71.      Inline ($50/                     {PUSH AX}
  72.              $53/                     {PUSH BX}
  73.              $51/                     {PUSH CX}
  74.              $52/                     {PUSH DX}
  75.              $57/                     {PUSH DI}
  76.              $56/                     {PUSH SI}
  77.              $06/                     {PUSH ES}
  78.              $1E/                     {PUSH DS}
  79.              $FB/                     {STI}
  80.              $2E/$A1/Data_Segment/    {MOV AX,[CS:Data_Segment]}
  81.              $8E/$D8);                {MOV DS,AX}
  82.      RS_Error:=Port[RS232[COM].LSR] and $1E;
  83.      Buffer[Buf_Tail]:=Port[RS232[COM].RBR];
  84.      Buf_Tail:=(Buf_Tail+1) mod 4096;
  85.      Inline ($FA);                    {CLI}
  86.      Port[$20]:=$20;   {Clear Interrupt flag}
  87.      Inline ($1F/                     {POP DS}
  88.              $07/                     {POP ES}
  89.              $5E/                     {POP SI}
  90.              $5F/                     {POP DI}
  91.              $5A/                     {POP DX}
  92.              $59/                     {POP CX}
  93.              $5B/                     {POP BX}
  94.              $58/                     {POP AX}
  95.              $8B/$E5/                 {MOV SP,BP}
  96.              $5D/                     {POP BP}
  97.              $CF); {Return}           {IRET}
  98.    End;  {of RS232_Interrupt}
  99.  
  100.  
  101. Procedure RS232_Init(Speed:Baud;P:Parity;Stop,Length:Byte);
  102.  
  103.      {This procedure uses Interrupt 14
  104.       to initialize the serial port.}
  105.  
  106.    Begin
  107.      Regs.DX:=Com-1;
  108.      Regs.AX:=Ord(Speed)*32 + Ord(P)*8 + (Stop-1)*4 + Length-5;
  109.      Intr($14,Regs);
  110.    End;  {of RS232_Init}
  111.  
  112.  
  113. Function RS232_Out(Param:Byte):Boolean;
  114. Var Counter:Real;
  115.  
  116.      {This function outputs a byte to the serial port.
  117.       In the event of a timeout, a value of TRUE is returned.
  118.       A timeout occurs if we cannot get Data Set Ready,
  119.       Clear to Send, and an empty transmit holding register
  120.       after 65535 attempts.}
  121.  
  122.    Begin
  123.      Counter:=0;
  124.      Port[RS232[COM].MCR]:=$0B;
  125.      While
  126.        ((Port[RS232[COM].MSR] and $30) <> $30)  {DSR and CTS}
  127.      and
  128.        ((Port[RS232[COM].LSR] and $20) <> $20)  {Tr. Reg empty}
  129.      and
  130.        (Counter < 65535.0) do                   {Timeout}
  131.           Counter:=Counter+1;
  132.      If Counter = 65535.0 then
  133.         RS232_Out:=True        {We timed out}
  134.      Else
  135.        Begin
  136.          Port[RS232[COM].THR]:=Param;
  137.          RS232_Out:=False;
  138.        End;
  139.    End;
  140.  
  141.  
  142. Procedure Initialize;
  143.  
  144.      {This procedure does the following:
  145.       1)  Changes the appropriate interrupt vector to point to
  146.           RS232_Interrupt.
  147.       2)  Enables the appropriate interrupt on the PC interrupt
  148.           controller.
  149.       3)  Enables the "data ready" interrupt on serial board.}
  150.  
  151.      Begin
  152.        Regs.AX:=$250D-Com;
  153.        Regs.DS:=CSEG;
  154.        Regs.DX:=Ofs(RS232_Interrupt);
  155.        MSDos(Regs);     {Set up interrupt vector}
  156.        If COM = 1 then
  157.          Port[$21]:=Port[$21] and $EF  {Enable IRQ4}
  158.        else
  159.          Port[$21]:=Port[$21] and $F7; {Enable IRQ3}
  160.        Port[RS232[COM].LCR]:=Port[RS232[COM].LCR] and $7F;
  161.        Port[RS232[COM].IER]:=1;
  162.        Port[RS232[COM].MCR]:=$08;
  163.      End;  {of Initialize}
  164.  
  165.  
  166. Procedure Cleanup;
  167.  
  168.      {This procedure disables the "data ready" interrupt.}
  169.  
  170.      Begin
  171.        Port[$21]:=Port[$21] or $18;
  172.        Port[RS232[COM].LCR]:=Port[RS232[COM].LCR] and $7F;
  173.        Port[RS232[COM].IER]:=0;
  174.        Port[RS232[COM].MCR]:=0;
  175.      End;  {of Cleanup}
  176.  
  177.  
  178. Procedure TTY;
  179.  
  180.      {This procedure provides basic terminal emulation.
  181.       Characters read from the keyboard are sent to the serial
  182.       port.  Characters read from the serial port are sent to
  183.       the screen.  The procedure is terminated by typing a
  184.       CTRL-Z.}
  185.  
  186.      Begin
  187.        ClrScr;
  188.        Repeat  {This code does NOT suppress NULs!}
  189.          While Buf_Tail <> Buf_Head Do
  190.            Begin   {There is data in the buffer}
  191.              Write(TRM,Char(Buffer[Buf_Head]));
  192.              Buf_Head:=(Buf_Head+1) mod 4096;
  193.            End;
  194.          If Keypressed then
  195.            Begin   {Process a keystroke}
  196.              Char_In:=Keyin;
  197.              If Char_In <> 26 then  {Ctrl Z to end}
  198.                Begin
  199.                  If Char_in = 13 then
  200.                    Write(TRM,Char(10));
  201.                  If RS232_Out(Lo(Char_In)) then
  202.                    Writeln(TRM, '*** RS232 Timeout ***');
  203.                End;
  204.            End;
  205.        Until Char_In = 26;  {Ctrl Z}
  206.      End;  {of TTY}
  207.  
  208.  
  209. Begin   {Outer Block}
  210.   COM:=1;   {Default to COM1}
  211.   Buf_Head:=0;
  212.   Buf_Tail:=0;
  213.   Data_Segment:=DSEG;   {Store the contents of the DS register}
  214.   {Init port to 1200 Baud, Even parity, 1 Stop bit, 7 Data bits}
  215.   RS232_Init(B1200,Even,1,7);
  216.   Initialize;
  217.   TTY;
  218.   Cleanup;
  219. End.